package com.mayflygeek.mayflyask.framework.orm.impl;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.Serializable;
import java.util.List;

import javax.inject.Inject;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import com.google.common.collect.Lists;
import com.googlecode.genericdao.dao.hibernate.HibernateBaseDAO;
import com.googlecode.genericdao.search.SearchResult;
import com.mayflygeek.mayflyask.framework.orm.Hibernatify;
import com.mayflygeek.mayflyask.framework.orm.Query;
import com.mayflygeek.mayflyask.framework.orm.exception.NotFoundException;
import com.mayflygeek.mayflyask.framework.orm.exception.PersistenceException;

/**
 * @author 虫虫
 * @team 蜉蝣极客
 * @link www.mayflygeek.com
 * @Emial chongchong@mayflygeek.com
 * 
 */
@Component
public class HibernatifyImpl extends HibernateBaseDAO implements Hibernatify {

	@Inject
	public HibernatifyImpl(final SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}
	
	@Override
	public Session getSession() {
		return super.getSession();
	}

	@Override
	public <T, ID extends Serializable> T get(Class<T> type, ID id) {
		T result = this.find(type, id);
		if(result == null) {
			throw new NotFoundException(type, id , null);
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T, ID extends Serializable> List<T> get(Class<T> type, ID id, ID... rest) {
		return this.get(type, Lists.asList(checkNotNull(id), rest));
	}

	@Override
	public <T, ID extends Serializable> List<T> get(Class<T> type, Iterable<ID> ids) {
		final List<T> result = Lists.newArrayList();
		for(ID id : ids) {
			try {
				result.add(this.get(type, id));
			} catch(Exception e) {
				throw new NotFoundException(type, id, e);
			}
		}
		return result;
	}

	@Override
	public <T, ID extends Serializable> T find(Class<T> type, ID id) {
		return super._get(checkNotNull(type), checkNotNull(id));
	}

	@Override
	public <T> List<T> find(Class<T> type) {
		checkNotNull(type);
		return this.list(new QueryImpl<T, T>(type));
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T, ID extends Serializable> List<T> find(Class<T> type, ID id, ID... rest) {
		return this.find(type, Lists.asList(checkNotNull(id), rest));
	}

	@Override
	public <T, ID extends Serializable> List<T> find(Class<T> type, Iterable<ID> ids) {
		checkNotNull(ids);
		final List<T> result = Lists.newArrayList();
		for(ID id : ids) {
			result.add(this.find(type,id));
		}
		return result;
	}

	@Override
	public <T> T put(T entity) {
		checkNotNull(entity);
		try {
			super._saveOrUpdateIsNew(entity);
			return entity;
		} catch (Exception e) {
			throw new PersistenceException(entity, "保存", "出错！", e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> put(T entity, T... rest) {
		return this.put(Lists.asList(checkNotNull(entity), rest));
	}

	@Override
	public <T> List<T> put(List<? extends T> entities) {
		final List<T> result = Lists.newArrayList();
		for(T entity : entities) {
			this.put(entity);
			result.add(entity);
		}
		return result;
	}

	@Override
	public <T> T delete(T entity) {
		checkNotNull(entity);
		try {
			super._deleteEntity(entity);
			return entity;
		} catch(Exception e) {
			throw new PersistenceException(entity, " 删除", "出错！", e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> delete(T entity, T... rest) {
		return this.delete(Lists.asList(checkNotNull(entity), rest));
	}

	@Override
	public <T> List<T> delete(List<T> entities) {
		checkNotNull(entities);
		final List<T> result = Lists.newArrayList();
		for (T entity : entities) {
			result.add(this.delete(entity));
		}
		return result;
	}

	@Override
	public <ID extends Serializable> void deleteById(Class<?> type, ID id) {
		checkNotNull(type);
		checkNotNull(id);
		try {
			super._deleteById(type, id);
		} catch (Exception e) {
			throw new PersistenceException(type, id, "删除", "出错！", e);
		}

	}

	@SuppressWarnings("unchecked")
	@Override
	public <ID extends Serializable> void deleteById(Class<?> type, ID id, ID... rest) {
		this.delete(checkNotNull(type), Lists.asList(checkNotNull(id), rest));

	}

	@Override
	public <ID extends Serializable> void deleteById(Class<?> type, Iterable<ID> ids) {
		checkNotNull(ids);
		for(ID id : ids) {
			this.delete(type, id);
		}

	}

	@SuppressWarnings("unchecked")
	@Override
	public <T, RT> List<RT> list(Query<T, RT> query) {
		return super._search(checkNotNull(query.toSearch()));
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T, RT> RT unique(Query<T, RT> query) {
		return (RT) super._searchUnique(checkNotNull(query.toSearch()));
	}

	@Override
	public <T, RT> Page<RT> page(Query<T, RT> query) {
		checkNotNull(query);
		
		if (query.autoCount()) {
			@SuppressWarnings("unchecked")
			final SearchResult<RT> searchResult = super._searchAndCount(query.toSearch());
			final PageRequest pageable = new PageRequest(query.thePage(), query.pagesize());
			return new PageImpl<>(searchResult.getResult(),pageable,searchResult.getTotalCount());
		} else {
			final List<RT> results = this.list(query);
			final PageRequest pageable = new PageRequest(query.thePage(), query.pagesize());
			return new PageImpl<>(results,pageable,results.size());
			
		}
	}

	@Override
	public <T> int count(Class<T> type) {
		return super._count(checkNotNull(type));
	}

	@Override
	public <T, RT> int count(Query<T, RT> query) {
		return super._count(query.toSearch());
	}

}
